package ca.cbc.medialib.service;

import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import ca.cbc.medialib.Bootstrap;
import com.theplatform.authentication.token.api.exception.AuthenticationException;
import com.theplatform.data.api.client.ClientConfiguration;
import com.theplatform.data.api.exception.ObjectNotFoundException;
import com.theplatform.data.api.marshalling.PayloadForm;
import com.theplatform.data.api.objects.FieldInfo;
import com.theplatform.data.api.objects.type.CategoryInfo;
import com.theplatform.data.api.objects.type.Duration;
import com.theplatform.media.api.client.MediaClient;
import com.theplatform.media.api.client.ReleaseClient;
import com.theplatform.media.api.data.objects.Media;
import com.theplatform.media.api.data.objects.MediaFile;
import com.theplatform.media.api.data.objects.Release;
import com.theplatform.module.authentication.client.AuthenticationClient;

/**
 * MediaLibService class use to communicate between the platform SDK and Media Service Bus(nmsrc/msb)
 * Date: Jan 29, 2011
 *
 * @author Liu Yang (liu.yang@cbc.ca)
 */
class MediaLibService {
    private MediaClient mediaClient;
    private ReleaseClient releaseClient;


    public MediaLibService() {
        mediaClient = Bootstrap.instance.getMediaClient();
        releaseClient = Bootstrap.instance.getReleaseClient();
    }

    /**
     * @param username = MPS username, passwd = MPS password, accountIds = MPS account Ids.
     *                 To get all media across all accounts visible to the username, pass in a null for the account name.
     *                 e.g. "liu.yang@cbc.ca","Password",new String[]{"CBC Dev"});
     * @throws UnknownHostException
     * @throws AuthenticationException
     */
    @Deprecated
    public MediaLibService(String username, String passwd, String[] accountIds) throws UnknownHostException, AuthenticationException {
        // construct an authentication client with credentials
        AuthenticationClient authClient = new AuthenticationClient(
                "https://identity.auth.theplatform.com/idm",
                "mps/" + username, passwd, accountIds);

        // configure the token to expire after 1 minute
        authClient.setTokenDuration(60000);

        // set up the media client configuration.  this can only be set when the
        // client is created
        ClientConfiguration config = new ClientConfiguration();

        // make the client stream results from get() calls,
        // instead of buffering the objects in memory
        config.setStreamingResults(true);

        // payload form can be Atom, RSS, or JSON
        config.setPayloadForm(PayloadForm.JSON);

        // construct the Data Service client using the authentication client
        mediaClient = new MediaClient("http://mps.theplatform.com", authClient, config);
        releaseClient = new ReleaseClient("http://mps.theplatform.com", authClient, config);

        //authClient.signOutToken();
    }

    /**
     * This methods takes a release ID and will updated release according to custom field map
     * @param releaseId -- String
     * @param customInfoMap -- Map<String, String>
     */
//	public void updateReleaseCustomProperties(String releaseId, Map<String, String> customInfoMap) throws URISyntaxException, ObjectNotFoundException
//	{
//		try{
//			Release release = releaseClient.get(new URI(releaseId), null);
//
//			//fetch name space from "genre" field
//			String mediaId = getReleaseProperties(releaseId).get("mediaIdURI");
//			Media media = mediaClient.get(new URI(mediaId), null, null, null);
//
//			String fieldNamespace = null;
//			for(FieldInfo field : media.getCustomValues().keySet())
//			{
//				if(field.getFieldName().equals("genre"))
//				{
//					fieldNamespace = field.getNamespace();
//					break;
//				}
//			}
//
//			//update release customized fields
//			for(String key : customInfoMap.keySet())
//			{
//				FieldInfo field = new FieldInfo();
//				field.setFieldName(key);
//				field.setNamespace(fieldNamespace);
//				release.setCustomValue(field, customInfoMap.get(key));
//			}
//
//			// update the Release object (a "put" notification should appear)
//			releaseClient.update(release);
//		} catch (URISyntaxException e) {
//			throw e;
//		} catch (ObjectNotFoundException e) {
//			throw e;
//		}
//	}

    /**
     * This methods takes a media ID and will updated media according to custom field map
     * @param mediaId -- String
     * @param customInfoMap -- Map<String, String>
     */
//	public void updateMediaCustomProperties(String mediaId, Map<String, String> customInfoMap) throws URISyntaxException, ObjectNotFoundException
//	{
//		try{
//			Media media = mediaClient.get(new URI(mediaId), null, null, null);
//
//			//fetch name space from "genre" field
//			String fieldNamespace = null;
//			for(FieldInfo field : media.getCustomValues().keySet())
//			{
//				if(field.getFieldName().equals("genre"))
//				{
//					fieldNamespace = field.getNamespace();
//					break;
//				}
//			}
//
//			//update media customized fields
//			for(String key : customInfoMap.keySet())
//			{
//				FieldInfo field = new FieldInfo();
//				field.setFieldName(key);
//				field.setNamespace(fieldNamespace);
//				media.setCustomValue(field, customInfoMap.get(key));
//			}
//
//			// update the Media object
//			mediaClient.update(media);
//		} catch (URISyntaxException e) {
//			throw e;
//		} catch (ObjectNotFoundException e) {
//			throw e;
//		}
//	}

    /**
     * This methods takes a media ID and will return all the releases IDs associate with this media
     *
     * @param mediaId -- String
     * @return releaseInfoMap -- List<String>
     */
    public List<String> getMediaReleaseIds(String mediaId) throws URISyntaxException, ObjectNotFoundException {
        List<String> releaseIds = null;
        try {
            Media media = mediaClient.get(new URI(mediaId), null, null, null);
            releaseIds = new ArrayList<String>();
            MediaFile[] mediaFileArray = media.getContent();
            if (mediaFileArray != null)
                for (MediaFile file : mediaFileArray) {
                    Release[] rArray = file.getReleases();
                    if (rArray != null)
                        for (Release r : rArray)
                            releaseIds.add(r.getId().toString());
                }
        } catch (URISyntaxException e) {
            throw e;
        } catch (ObjectNotFoundException e) {
            throw e;
        }

        return releaseIds;
    }

    /**
     * This methods takes a release ID and will return related release information
     *
     * @param releaseId -- String
     * @return releaseInfoMap -- Map<String, String>
     */
    public Map<String, String> getReleaseProperties(String releaseId) throws URISyntaxException, ObjectNotFoundException {
        Map<String, String> releaseInfoMap = null;
        try {
            Release release = releaseClient.get(new URI(releaseId), null);

            releaseInfoMap = new HashMap<String, String>();
            releaseInfoMap.put("mediaIdURI", release.getMediaId().toString());
            releaseInfoMap.put("delivery", release.getDelivery().toString());
            releaseInfoMap.put("releaseURL", release.getUrl());
            releaseInfoMap.put("airdate", release.getAdded().toString());
            releaseInfoMap.put("updatedDate", release.getUpdated().toString());

            //put custom fields into map
            if (release.getCustomValues() != null)
                for (FieldInfo field : release.getCustomValues().keySet()) {
                    String value = release.getCustomValues().get(field).toString();
                    String fieldName = field.getFieldName();

                    if (value.equals("(not specified)"))
                        releaseInfoMap.put(fieldName, null);
                    else
                        releaseInfoMap.put(fieldName, value);
                }
        } catch (URISyntaxException e) {
            throw e;
        } catch (ObjectNotFoundException e) {
            throw e;
        }

        return releaseInfoMap;
    }

    /**
     * This methods takes a media ID and will return related media informations
     *
     * @param mediaId -- String
     * @return mediaInfoMap -- Map<String, String>
     */
    public Map<String, String> getMediaProperties(String mediaId) throws URISyntaxException, ObjectNotFoundException {
        Map<String, String> mediaInfoMap = null;
        try {
            Media media = mediaClient.get(new URI(mediaId), null, null, null);
            mediaInfoMap = new HashMap<String, String>();
            mediaInfoMap.put("keywords", media.getKeywords());
            mediaInfoMap.put("description", media.getDescription());
            mediaInfoMap.put("title", media.getTitle());
            mediaInfoMap.put("addedDate", media.getAdded().toString());
            mediaInfoMap.put("thumbnailURL", media.getDefaultThumbnailUrl());

            //put run time
            String runTimeStr = null;
            MediaFile[] mediaFileArray = media.getContent();
            if (mediaFileArray != null && mediaFileArray.length > 0) {
                Duration d = mediaFileArray[0].getDuration();
                runTimeStr = d.getHour() + ":" + singleDigitTimeWrapper(d.getMinute()) + ":" + singleDigitTimeWrapper(d.getSecond());
            }
            mediaInfoMap.put("runtime", runTimeStr);

            //put category
            String categoryStr = null;
            CategoryInfo[] cf = media.getCategories();
            if (cf != null && cf.length > 0)
                categoryStr = cf[0].getName();
            mediaInfoMap.put("category", categoryStr);

            //put custom fields into map
            for (FieldInfo field : media.getCustomValues().keySet()) {
                String value = media.getCustomValues().get(field).toString();
                String fieldName = field.getFieldName();

                if (value.equals("(not specified)"))
                    mediaInfoMap.put(fieldName, null);
                else
                    mediaInfoMap.put(fieldName, value);
            }
        } catch (URISyntaxException e) {
            throw e;
        } catch (ObjectNotFoundException e) {
            throw e;
        }

        return mediaInfoMap;
    }


    /**
     * This methods put a zero before a single digit number
     *
     * @param n -- long
     * @return String
     */
    protected String singleDigitTimeWrapper(long n) {
        if (n < 10 && n >= 0)
            return "0" + n;
        else
            return String.valueOf(n);
    }


}
